package com.yami.shop.platform.task;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yami.shop.bean.model.User;
import com.yami.shop.common.bean.Minio;
import com.yami.shop.common.util.OssMultipartFile;
import com.yami.shop.common.util.pdfUtil.PdfUtils;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.nft.common.model.NftApply;
import com.yami.shop.nft.common.service.NftApplyService;
import com.yami.shop.personnft.common.dao.PersonNftAccountMapper;
import com.yami.shop.personnft.common.model.*;
import com.yami.shop.personnft.common.service.PersonShareRecordService;
import com.yami.shop.service.AttachFileService;
import com.yami.shop.service.UserService;
import com.yami.shop.user.common.model.UserGasLog;
import com.yami.shop.user.common.service.UserGasInfoService;
import com.yami.shop.user.common.service.UserGasLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.context.ApplicationContext;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yami.shop.bean.enums.SceneType;
import com.yami.shop.bean.enums.TradeType;
import com.yami.shop.bean.event.AssetTrendsEvent;
import com.yami.shop.bean.event.UpdateRightsEvent;
import com.yami.shop.bean.model.PersonNftApply;
import com.yami.shop.bean.vo.AssetTrendsVO;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.personnft.common.dao.PersonNftApplyMapper;
import com.yami.shop.personnft.common.service.PersonNftService;
import com.yami.shop.personnft.common.service.PersonShareReceiveService;
import com.yami.shop.personnft.common.service.PersonShareService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 分享定时任务
 */
@Component
@Slf4j
public class PersonShareTask {

    @Autowired
    private PersonShareReceiveService personShareReceiveService;
    @Autowired
    private PersonShareService personShareService;
    @Autowired
    private PersonNftApplyMapper personNftApplyMapper;
    @Autowired
    private PersonNftService personNftService;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private PersonNftAccountMapper personNftAccountMapper;
    @Autowired
    private PersonShareRecordService personShareRecordService;
    @Autowired
    private NftApplyService nftApplyService;
    @Autowired
    private UserService userService;
    @Autowired
    private AttachFileService attachFileService;
    @Autowired
    private ShopConfig shopConfig;
    @Autowired
    private UserGasInfoService userGasInfoService;
    @Autowired
    private UserGasLogService userGasLogService;

    /**
     * 分享转移定时任务
     */
    @XxlJob("shareTransfer")
    public void shareTransfer() {
        // 获取待转移分享记录
        QueryWrapper<PersonShareReceive> personShareReceiveQueryWrapper = new QueryWrapper<>();
        personShareReceiveQueryWrapper.eq("status", "0");
        List<PersonShareReceive> list = personShareReceiveService.list(personShareReceiveQueryWrapper);
        if (ObjectUtil.isEmpty(list)) {
            return;
        }
        // 转移币
        for (PersonShareReceive personShareReceive : list) {
            // 获取发送人
            PersonShare byId = personShareService.getById(personShareReceive.getShareId());
            try {
                sharePersonnft(personShareReceive.getTokensId(), personShareReceive.getUserId(), byId.getId(), personShareReceive.getId());
                personShareReceive.setStatus(1);
            } catch (Exception e) {
                personShareReceive.setStatus(2);
                log.debug("分享转移持仓异常=============={}", e);
            }
            // 修改转移记录
            personShareReceiveService.updateById(personShareReceive);
        }

    }

    /**
     * 过期定时任务
     */
    @XxlJob("expireShare")
    public void expireShare() {
        QueryWrapper<PersonShare> personShareQueryWrapper = new QueryWrapper<>();
        personShareQueryWrapper.lt("expiration_time", new Date());
        personShareQueryWrapper.eq("status", 0);
        personShareQueryWrapper.eq("type", "1");//分享转增
        List<PersonShare> list = personShareService.list(personShareQueryWrapper);
        // 过期分享 --- 币解冻
        for (PersonShare personShare : list) {
            // 获取 未领取的币
            QueryWrapper<PersonShareRecord> personShareRecordQueryWrapper = new QueryWrapper<>();
            personShareRecordQueryWrapper.eq("share_id", personShare.getId());
            personShareRecordQueryWrapper.eq("status", 0);
            List<PersonShareRecord> personShareRecords = personShareRecordService.list(personShareRecordQueryWrapper);
            String tokens = personShareRecords.stream().map(PersonShareRecord::getTokensId).collect(Collectors.joining(","));
            // 币解冻
            try{
                unfreezePersonnft(personShare.getUserId(), personShareRecords.size(), personShare.getId(), tokens);
                userGasInfoService.saveGasNumberByUserId(personShare.getUserId(),personShareRecords.size());
                // DTC++ gas 记录保存
                UserGasLog userGasLog = new UserGasLog();
                userGasLog.setCreateTime(new Date());
                userGasLog.setIoType(1); // 收支类型 0支出 1收入
                userGasLog.setType(9);   // gas记录 类型
                userGasLog.setIsPayed(1);  // 0未支付
                userGasLog.setUserId(personShare.getUserId());
                userGasLog.setGasId(personShare.getId());
                userGasLog.setTabStatus(1); //已处理--- 已发送
                userGasLog.setPateTab(personShare.getChainCode());  //平台
                userGasLog.setGasNum(Integer.parseInt(personShareRecords.size()+""));
                userGasLogService.save(userGasLog);


            }catch (Exception e){
                log.debug("解冻异常",e);
                personShare.setStatus(2);
                personShareService.updateById(personShare);
                continue;
            }
            // 修改 分享 币记录状态
            personShareRecords.forEach(s -> s.setStatus(2));
            personShareRecordService.updateBatchById(personShareRecords);
            // 分享状态修改
            personShare.setStatus(2);
            personShareService.updateById(personShare);
        }


    }


    private void sharePersonnft(String tokenIds, String userId, Long shareId, Long receiveId) {
        PersonNftApply personNftApply = personNftApplyMapper.selectByRemarkAndSceneTypeId(shareId, 23);
        List<PersonNft> lsitAdd = new ArrayList<>();
        List<PersonNft> lsit = new ArrayList<>();
        List<String> tokenList = Arrays.asList(tokenIds.split(","));
        List<String> prodCode = new ArrayList<>();
        for (String tokenId : tokenList) {
            //1增加受赠方持仓
            PersonNft personNft = PersonNft.builder().tokenId(tokenId).status(4).build();
            List<PersonNft> personNfts = personNftService.listByParam(personNft);

            //4 转增方减去持仓
            List<PersonNft> personNfts2 = personNfts.stream().filter(s -> s.getUserId().equals(personNftApply.getUserId()) && s.getStatus() == 1).collect(Collectors.toList());
            if (personNfts2.size() != 1) {
                throw new YamiShopBindException("转赠方持仓数据异常");
            } else {
                //受赠方减去持仓
                PersonNft personNft1 = personNfts2.get(0);
                personNft1.setStatus(2);
                personNft1.setUpdateTime(DateUtil.date());
                personNft1.setSceneType(Integer.valueOf(SceneType.ShareReduce.getCode()));
                lsit.add(personNft1);
            }

            //校验受赠方是否有该未删除的tokenid
            List<PersonNft> list = personNfts.stream().filter(s -> s.getUserId().equals(userId) && s.getStatus() != 2).collect(Collectors.toList());
            if (list.size() > 0) {
                throw new YamiShopBindException("受赠方持仓数据异常");
            }
            List<PersonNft> list1 = personNfts.stream().filter(s -> s.getUserId().equals(userId) && s.getStatus() == 2).collect(Collectors.toList());
            if (list1.size() > 0) {
                //如果受赠方已有记录直接修改状态
                PersonNft personNft1 = list1.get(0);
                prodCode.add(personNft1.getDawProductCode());
                personNft1.setStatus(0);
                personNft1.setCreateTime(DateUtil.date());
                personNft1.setSceneType(Integer.valueOf(SceneType.ShareAdd.getCode()));
                lsit.add(personNft1);
            } else {
                //受赠方添加持仓 -没有新增一条
                PersonNft personNft1 = personNfts.get(0);
                PersonNft person = PersonNft.builder()
                        .status(0)
                        .id(IdUtil.getSnowflake().nextIdStr())
                        .createTime(DateUtil.date())
                        .userId(userId)
                        .tokenId(tokenId)
                        .productId(personNftApply.getProductId())
                        .dawProductCode(personNft1.getDawProductCode())
                        .denomId(personNftApply.getDenomId())
                        .channelCode(personNftApply.getChannelCode())
                        .chainCode(personNftApply.getChainCode())
                        .sceneType(Integer.valueOf(SceneType.ShareAdd.getCode()))
                        .build();
                // 修改文件
                NftApply nftApply = nftApplyService.getNftApplyAndImgInfoByDenomId(personNftApply.getDenomId());
                if(ObjectUtil.isNotEmpty(nftApply.getNftApplyImg().getIsReplaceUrl()) && nftApply.getNftApplyImg().getIsReplaceUrl() == 1){
                    String sourceUrlPdf = JSONObject.parseObject(nftApply.getNftApplyImg().getImgUrl()).getString("sourceUrlPdf");
                    // 获取用户 实名 信息
                    User user = userService.getUserByUserId(userId);
                    // 上传文件信息
                    Map<String, Object> keyWordMap = new HashMap<>();
                    keyWordMap.put("name",user.getRealName());
                    person.setSourceUrl(updateSourceImg(keyWordMap,sourceUrlPdf));
                }
                lsitAdd.add(person);
            }
            // 权益转移修改
            applicationContext.publishEvent(new UpdateRightsEvent(tokenId, userId, personNftApply.getUserId()));
        }
        if (lsit.size() > 0) {
            personNftService.updateBatchById(lsit);
        }
        if (lsitAdd.size() > 0) {
            personNftService.saveBatch(lsitAdd);
        }
        //2增加受赠方藏品记录
        String idStr = IdUtil.getSnowflake().nextIdStr();
        PersonNftAccount personNftAccount = PersonNftAccount.builder()
                .sceneType(Integer.valueOf(SceneType.ShareAdd.getCode()))
                .content(tokenIds)
                .dawProductCode(String.join(",", prodCode))
//                .dawNameId(personNftApply.getDawNameId())
                .denomId(personNftApply.getDenomId())
                .userId(userId)
                .createTime(DateUtil.date())
                .id(idStr)
                .count(tokenList.size())
                .channelType(personNftApply.getChannelType())
                .productId(personNftApply.getProductId())
                .orderId(receiveId + "")
                .chainCode(personNftApply.getChainCode())
                .channelCode(personNftApply.getChannelCode())
                .build();
        personNftAccountMapper.save(personNftAccount);
        //5 转增方转增记录
        PersonNftAccount personNftAccount1 = PersonNftAccount.builder()
                .sceneType(Integer.valueOf(SceneType.ShareReduce.getCode()))
                .content(tokenIds)
                .dawProductCode(String.join(",", prodCode))
//                .dawNameId(personNftApply.getDawNameId())
                .denomId(personNftApply.getDenomId())
                .userId(personNftApply.getUserId())
                .createTime(DateUtil.date())
                .id(IdUtil.getSnowflake().nextIdStr())
                .count(tokenList.size())
                .productId(personNftApply.getProductId())
                .orderId(receiveId + "")
                .channelType(personNftApply.getChannelType())
                .chainCode(personNftApply.getChainCode())
                .channelCode(personNftApply.getChannelCode())
                .build();
        personNftAccountMapper.save(personNftAccount1);
        List<AssetTrendsVO> list = new ArrayList<>();
        for (String tokenId : tokenList) {
            AssetTrendsVO trendsVO = AssetTrendsVO.builder().denomId(personNftApply.getDenomId()).tokenId(tokenId)
                    .fromUserId(personNftApply.getUserId()).toUserId(userId).outId(idStr).prodId(personNftApply.getProductId()).build();
            list.add(trendsVO);
        }
        applicationContext.publishEvent(new AssetTrendsEvent(TradeType.SHARE_ENVELOPE.getValue(), list));
    }

    private void unfreezePersonnft(String userId, Integer tokenNum, Long shareId, String tokenIds) {

        // 查询对应持仓个数
        PersonNft personNft = PersonNft.builder().status(1).userId(userId).build();
        PersonNftApply personNftApply = personNftApplyMapper.selectByRemarkAndSceneTypeId(shareId, 23);
        personNft.setDenomId(personNftApply.getDenomId());
        personNft.setTokenIds(Arrays.asList(tokenIds.split(",")));
        List<PersonNft> personNfts = personNftService.listByParam(personNft);
        if (personNfts.size() < tokenNum) {
            throw new YamiShopBindException("持仓状态异常");
        }
        // 添加账单表
        List<PersonNft> freezePerson = personNfts.subList(0, tokenNum);
        String contenStr = freezePerson.stream().map(PersonNft::getTokenId).collect(Collectors.joining(","));
        String dawProductCode = freezePerson.stream().map(PersonNft::getDawProductCode).collect(Collectors.joining(","));

        // 自己领取自己红包 / 红包退回 -- 解冻过程
        PersonNftAccount personNftAccount = PersonNftAccount.builder()
                .sceneType(Integer.valueOf(SceneType.ShareUnFreeze.getCode()))
                .content(contenStr)
                .dawProductCode(dawProductCode)
//                .dawNameId(freezePerson.get(0).getDawNameId())
                .denomId(freezePerson.get(0).getDenomId())
                .userId(userId)
                .createTime(DateUtil.date())
                .id(IdUtil.getSnowflake().nextIdStr())
                .channelType(personNftApply.getChannelType())
                .chainCode(personNftApply.getChainCode())
                .channelCode(personNftApply.getChannelCode())
                .count(tokenNum)
                .productId(freezePerson.get(0).getProductId())
                .orderId(shareId + "")
                .build();
        personNftAccountMapper.save(personNftAccount);

        // 冻结持仓
        freezePerson.forEach(s -> s.setStatus(0));
        personNftService.updateBatch(freezePerson);

    }


    private String updateSourceImg(Map<String, Object> keyWordMap, String sourceUrlPdf) {
        try{
            Minio minio = shopConfig.getMinio();
            URL url = new URL(minio.getEndpoint() + "/" + minio.getBucketName() + "/" + sourceUrlPdf);
            URLConnection urlConnection = url.openConnection();
            urlConnection.connect();
            ByteArrayOutputStream qrOutputStream = new ByteArrayOutputStream();
            PdfUtils.generatePdf(urlConnection.getInputStream(), qrOutputStream, keyWordMap,null,85f);
            //保存图片
            PDDocument document = PDDocument.load(qrOutputStream.toByteArray());
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            BufferedImage image = pdfRenderer.renderImageWithDPI(0, 300); // 使用300dpi解析第一页，可以自行调整dpi大小
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(image, "JPEG", outputStream);
            MultipartFile ossMultipartFile = new OssMultipartFile("111.jpg", ".jpg", outputStream.toByteArray());
            String fileName = attachFileService.uploadFile(ossMultipartFile.getBytes(), UUID.randomUUID() + ".jpg");
            return fileName;
        }catch (Exception e){
            log.error("PDF生成异常{}",e);
            return "";
        }
    }

}
